Micron Document
pintobyte rngit


Displaying Raw • Download

xous-core/services/com/src/lib.rs main (17e4bce8) Text, 31.69 KB

#![cfg_attr(target_os = "none", no_std)]

/// This is the API that other servers use to call the COM. Read this code as if you
/// are calling these functions inside a different process.
pub mod api;

use std::cell::RefCell;
use std::collections::VecDeque;

pub use api::*;
pub use com_rs::serdes::Ipv4Conf;
use com_rs::{DhcpState, LinkState};
use num_traits::{FromPrimitive, ToPrimitive};
use xous::{CID, Error, Message, msg_scalar_unpack, send_message};
use xous_ipc::Buffer;
use xous_semver::SemVer;

/// mapping of the callback function to the library user
/// this exists in the library user's memory space, so we can have up to one
/// callback per library user.
static mut BATTSTATS_CB: Option<fn(BattStats)> = None;

/// handles callback messages from the COM server, in the library user's process space.
fn battstats_server(sid0: usize, sid1: usize, sid2: usize, sid3: usize) {
let sid = xous::SID::from_u32(sid0 as u32, sid1 as u32, sid2 as u32, sid3 as u32);
loop {
let msg = xous::receive_message(sid).unwrap();
match FromPrimitive::from_usize(msg.body.id()) {
Some(Callback::BattStats) => msg_scalar_unpack!(msg, lo, hi, _, _, {
let bs: BattStats = [lo, hi].into();
unsafe {
if let Some(cb) = BATTSTATS_CB {
cb(bs)
}
}
}),
Some(Callback::Drop) => {
break; // this exits the loop and kills the thread
}
None => (),
}
}
xous::destroy_server(sid).unwrap();
}
#[derive(Debug)]
pub struct Com {
conn: CID,
battstats_sid: Option<xous::SID>,
ec_lock_id: Option<[u32; 4]>,
ec_acquired: bool,
/// this is a hack to make loopbacks work on smoltcp. Work-around taken from Redox, but tracking this
/// issue as well: <https://github.com/smoltcp-rs/smoltcp/issues/50> and <https://github.com/smoltcp-rs/smoltcp/issues/55>
loopback_buf: RefCell<VecDeque<Vec<u8>>>,
}
impl Com {
pub fn new(xns: &xous_names::XousNames) -> Result<Self, xous::Error> {
REFCOUNT.fetch_add(1, Ordering::Relaxed);
let conn =
xns.request_connection_blocking(api::SERVER_NAME_COM).expect("Can't connect to COM server");
Ok(Com {
conn,
battstats_sid: None,
ec_lock_id: None,
ec_acquired: false,
loopback_buf: RefCell::new(VecDeque::new()),
})
}

pub fn conn(&self) -> CID { self.conn }

pub fn getop_backlight(&self) -> u32 { Opcode::SetBackLight.to_u32().unwrap() }

#[deprecated(
note = "Uses susres.immediate_poweroff() instead, as power sequencing requirements have changed."
)]
pub fn power_off_soc(&self) -> Result<(), xous::Error> {
send_message(self.conn, Message::new_scalar(Opcode::PowerOffSoc.to_usize().unwrap(), 0, 0, 0, 0))
.map(|_| ())
}

/// ship mode is synchronous, so that we can schedule order-of-operation dependent tasks around it
pub fn ship_mode(&self) -> Result<(), xous::Error> {
let response = send_message(
self.conn,
Message::new_blocking_scalar(Opcode::ShipMode.to_usize().unwrap(), 0, 0, 0, 0),
)?;
if let xous::Result::Scalar1(_) = response {
Ok(())
} else {
log::error!("ship_mode failed to execute");
Err(xous::Error::InternalError)
}
}

pub fn link_reset(&self) -> Result<(), xous::Error> {
send_message(
self.conn,
Message::new_blocking_scalar(Opcode::LinkReset.to_usize().unwrap(), 0, 0, 0, 0),
)
.map(|_| ())
}

pub fn ping(&self, value: usize) -> Result<usize, xous::Error> {
if let xous::Result::Scalar1(pong) = send_message(
self.conn,
Message::new_blocking_scalar(Opcode::Ping.to_usize().unwrap(), value, 0, 0, 0),
)? {
Ok(pong)
} else {
Err(xous::Error::InternalError)
}
}

pub fn reseed_ec_trng(&self) -> Result<(), xous::Error> {
send_message(self.conn, Message::new_scalar(Opcode::ReseedTrng.to_usize().unwrap(), 0, 0, 0, 0))
.map(|_| ())
}

pub fn get_ec_uptime(&self) -> Result<u64, xous::Error> {
let response = send_message(
self.conn,
Message::new_blocking_scalar(Opcode::GetUptime.to_usize().unwrap(), 0, 0, 0, 0),
)?;
if let xous::Result::Scalar2(lsb, msb) = response {
Ok(lsb as u64 | (msb as u64) << 32)
} else {
Err(xous::Error::InternalError)
}
}

pub fn get_wf200_fw_rev(&self) -> Result<SemVer, xous::Error> {
let response = send_message(
self.conn,
Message::new_blocking_scalar(Opcode::Wf200Rev.to_usize().unwrap(), 0, 0, 0, 0),
)?;
if let xous::Result::Scalar1(rev) = response {
Ok(SemVer {
maj: ((rev >> 16) & 0xFF) as u16,
min: ((rev >> 8) & 0xFF) as u16,
rev: (rev & 0xFF) as u16,
extra: 0,
commit: None,
})
} else {
panic!("unexpected return value: {:#?}", response);
}
}

/// this is the Git rev of the *soc*, not the firmware.
pub fn get_ec_git_rev(&self) -> Result<(u32, bool), Error> {
let response = send_message(
self.conn,
Message::new_blocking_scalar(Opcode::EcGitRev.to_usize().unwrap(), 0, 0, 0, 0),
)?;
if let xous::Result::Scalar2(rev, dirty) = response {
let dirtybool: bool;
if dirty == 0 {
dirtybool = false;
} else {
dirtybool = true;
}
Ok((rev as u32, dirtybool))
} else {
panic!("unexpected return value: {:#?}", response);
}
}

/// this is the rev of the firmware
pub fn get_ec_sw_tag(&self) -> Result<SemVer, Error> {
let response = send_message(
self.conn,
Message::new_blocking_scalar(Opcode::EcSwTag.to_usize().unwrap(), 0, 0, 0, 0),
)?;
if let xous::Result::Scalar1(rev) = response {
Ok(SemVer {
maj: ((rev >> 24) & 0xff) as u16,
min: ((rev >> 16) & 0xff) as u16,
rev: ((rev >> 8) & 0xff) as u16,
extra: ((rev >> 0) & 0xff) as u16,
commit: None,
})
} else {
panic!("unexpected return value: {:#?}", response);
}
}

pub fn send_pds_line(&self, s: &String) -> Result<(), Error> {
use core::fmt::Write;
let mut clone_s: String = String::new();
write!(clone_s, "{}", s.as_str()).map_err(|_| xous::Error::AccessDenied)?;

let buf = Buffer::into_buf(clone_s).or(Err(xous::Error::InternalError))?;
buf.lend(self.conn, Opcode::Wf200PdsLine.to_u32().unwrap()).map(|_| ())
}

/// this kicks off an async callback for battery status at some later time
pub fn req_batt_stats(&self) -> Result<(), xous::Error> {
send_message(self.conn, Message::new_scalar(Opcode::BattStatsNb.to_usize().unwrap(), 0, 0, 0, 0))
.map(|_| ())
}

/// this allows the caller to provide a hook to handle the callback
pub fn hook_batt_stats(&mut self, cb: fn(BattStats)) -> Result<(), xous::Error> {
if unsafe { BATTSTATS_CB }.is_some() {
return Err(xous::Error::MemoryInUse);
}
unsafe { BATTSTATS_CB = Some(cb) };
if self.battstats_sid.is_none() {
let sid = xous::create_server().unwrap();
self.battstats_sid = Some(sid);
let sid_tuple = sid.to_u32();
xous::create_thread_4(
battstats_server,
sid_tuple.0 as usize,
sid_tuple.1 as usize,
sid_tuple.2 as usize,
sid_tuple.3 as usize,
)
.unwrap();
xous::send_message(
self.conn,
Message::new_scalar(
Opcode::RegisterBattStatsListener.to_usize().unwrap(),
sid_tuple.0 as usize,
sid_tuple.1 as usize,
sid_tuple.2 as usize,
sid_tuple.3 as usize,
),
)
.unwrap();
}
Ok(())
}

pub fn get_batt_stats_blocking(&mut self) -> Result<BattStats, xous::Error> {
let response = send_message(
self.conn,
Message::new_blocking_scalar(Opcode::BattStats.to_usize().unwrap(), 0, 0, 0, 0),
)?;
if let xous::Result::Scalar2(rs0, rs1) = response {
let bs: BattStats = [rs0, rs1].into();
Ok(bs)
} else {
Err(xous::Error::InternalError)
}
}

pub fn get_more_stats(&mut self) -> Result<[u16; 15], xous::Error> {
let alloc_stats: [u16; 15] = [0; 15];
let mut buf = Buffer::into_buf(alloc_stats).or(Err(xous::Error::InternalError))?;
buf.lend_mut(self.conn, Opcode::MoreStats.to_u32().unwrap())?;

let stats: [u16; 15] = buf.to_original::<[u16; 15], _>().unwrap();
Ok(stats)
}

pub fn poll_usb_cc(&mut self) -> Result<(bool, [u16; 3], u8), xous::Error> {
let response = send_message(
self.conn,
Message::new_blocking_scalar(Opcode::PollUsbCc.to_usize().unwrap(), 0, 0, 0, 0),
)?;
if let xous::Result::Scalar2(val1, val2) = response {
let event = if ((val1 >> 16) & 0xff) == 0 { false } else { true };
let regs: [u16; 3] =
[(val1 & 0xFFFF) as u16, (val2 & 0xFFFF) as u16, ((val2 >> 16) & 0xFF) as u16];
let rev: u8 = ((val1 >> 24) & 0xff) as u8;
Ok((event, regs, rev))
} else {
Err(xous::Error::InternalError)
}
}

pub fn wifi_disable(&self) -> Result<(), xous::Error> {
send_message(self.conn, Message::new_scalar(Opcode::Wf200Disable.to_usize().unwrap(), 0, 0, 0, 0))
.map(|_| ())
}

// as wifi_reset() re-initializes the wifi chip, call this after wifi_disable() to re-enable wifi
pub fn wifi_reset(&self) -> Result<usize, xous::Error> {
let ret = send_message(
self.conn,
Message::new_blocking_scalar(Opcode::Wf200Reset.to_usize().unwrap(), 0, 0, 0, 0),
)
.expect("couldn't send reset opcode");
if let xous::Result::Scalar1(time) = ret {
log::info!("WF200 reset took {}ms", time);
Ok(time)
} else {
Err(xous::Error::Timeout)
}
}

pub fn set_ssid_scanning(&self, enable: bool) -> Result<(), xous::Error> {
if enable {
send_message(self.conn, Message::new_scalar(Opcode::ScanOn.to_usize().unwrap(), 0, 0, 0, 0))
.map(|_| ())
} else {
send_message(self.conn, Message::new_scalar(Opcode::ScanOff.to_usize().unwrap(), 0, 0, 0, 0))
.map(|_| ())
}
}

// this function no longer works, must rely on the event-based response via ComInt mechanism
#[deprecated]
pub fn ssid_scan_updated(&self) -> Result<bool, xous::Error> {
if let xous::Result::Scalar1(avail) = send_message(
self.conn,
Message::new_blocking_scalar(Opcode::SsidCheckUpdate.to_usize().unwrap(), 0, 0, 0, 0),
)
.unwrap()
{
if avail != 0 { Ok(true) } else { Ok(false) }
} else {
Err(xous::Error::InternalError)
}
}

// superceded by ssid_fetch_as_list in versions later 0.9.5 (non-inclusive)
#[deprecated]
pub fn ssid_fetch_as_string(&self) -> Result<String, xous::Error> {
let ssid_list = String::new();
let mut buf = Buffer::into_buf(ssid_list).or(Err(xous::Error::InternalError))?;
buf.lend_mut(self.conn, Opcode::SsidFetchAsString.to_u32().unwrap())
.or(Err(xous::Error::InternalError))?;
let response = buf.to_original::<String, _>().unwrap();
Ok(response)
}

/// returns a vector of \\`(u8, String)\\` tuples that represent rssi + AP name
/// Note: this only returns the very most recent incremental scan results from the wifi chip directly.
/// The aggregated results of multiple scan passes are accessible from the connection manager via the
/// NetMgr object.
pub fn ssid_fetch_as_list(&self) -> Result<Vec<(u8, std::string::String)>, xous::Error> {
let ssid_alloc = SsidReturn::default();
let mut buf = Buffer::into_buf(ssid_alloc).or(Err(xous::Error::InternalError))?;
buf.lend_mut(self.conn, Opcode::SsidFetchAsStringV2.to_u32().unwrap())
.or(Err(xous::Error::InternalError))?;
let response = buf.to_original::<SsidReturn, _>().unwrap();
let mut ret = Vec::<(u8, std::string::String)>::new();
for ssid in response.list {
ret.push((ssid.rssi, ssid.name));
}
Ok(ret)
}

pub fn get_standby_current(&self) -> Result<Option<i16>, xous::Error> {
if let xous::Result::Scalar2(valid, current) = send_message(
self.conn,
Message::new_blocking_scalar(Opcode::StandbyCurrent.to_usize().unwrap(), 0, 0, 0, 0),
)
.unwrap()
{
if valid != 0 { Ok(Some(current as i16)) } else { Ok(None) }
} else {
Err(xous::Error::InternalError)
}
}

pub fn set_boost(&self, on: bool) -> Result<(), xous::Error> {
if on {
send_message(self.conn, Message::new_scalar(Opcode::BoostOn.to_usize().unwrap(), 0, 0, 0, 0))
.map(|_| ())
} else {
send_message(self.conn, Message::new_scalar(Opcode::BoostOff.to_usize().unwrap(), 0, 0, 0, 0))
.map(|_| ())
}
}

// numbers from 0-255 represent backlight brightness. Note that only the top 5 bits are used.
pub fn set_backlight(&self, main: u8, secondary: u8) -> Result<(), xous::Error> {
send_message(
self.conn,
Message::new_scalar(
Opcode::SetBackLight.to_usize().unwrap(),
(main >> 3) as usize,
(secondary >> 3) as usize,
0,
0,
),
)
.map(|_| ())
}

pub fn is_charging(&self) -> Result<bool, xous::Error> {
if let xous::Result::Scalar1(state) = send_message(
self.conn,
Message::new_blocking_scalar(Opcode::IsCharging.to_usize().unwrap(), 0, 0, 0, 0),
)
.unwrap()
{
if state != 0 { Ok(true) } else { Ok(false) }
} else {
Err(xous::Error::InternalError)
}
}

pub fn request_charging(&self) -> Result<(), xous::Error> {
send_message(self.conn, Message::new_scalar(Opcode::RequestCharging.to_usize().unwrap(), 0, 0, 0, 0))
.map(|_| ())
}

pub fn gyro_read_blocking(&self) -> Result<(u16, u16, u16, u16), xous::Error> {
if let xous::Result::Scalar2(x_y, z_id) = send_message(
self.conn,
Message::new_blocking_scalar(Opcode::ImuAccelReadBlocking.to_usize().unwrap(), 0, 0, 0, 0),
)
.unwrap()
{
let x = (x_y >> 16) as u16;
let y = (x_y & 0xffff) as u16;
let z = (z_id >> 16) as u16;
let id = (z_id & 0xffff) as u16;
Ok((x, y, z, id))
} else {
Err(xous::Error::InternalError)
}
}

pub fn flash_acquire(&mut self) -> Result<bool, xous::Error> {
let (id0, id1, id2, id3) = xous::create_server_id()?.to_u32();
self.ec_lock_id = Some([id0, id1, id2, id3]);
if let xous::Result::Scalar1(acquired) = send_message(
self.conn,
Message::new_blocking_scalar(
Opcode::FlashAcquire.to_usize().unwrap(),
id0 as usize,
id1 as usize,
id2 as usize,
id3 as usize,
),
)
.unwrap()
{
if acquired != 0 {
self.ec_acquired = true;
Ok(true)
} else {
self.ec_acquired = false;
Ok(false)
}
} else {
self.ec_acquired = false;
Err(xous::Error::InternalError)
}
}

pub fn flash_erase(&mut self, addr: u32, len: u32) -> Result<bool, xous::Error> {
if !self.ec_acquired {
return Err(xous::Error::AccessDenied);
}
let flashop = api::FlashRecord { id: self.ec_lock_id.unwrap(), op: api::FlashOp::Erase(addr, len) };
let mut buf = Buffer::into_buf(flashop).or(Err(xous::Error::InternalError))?;
buf.lend_mut(self.conn, Opcode::FlashOp.to_u32().unwrap())
.expect("couldn't send flash erase command");
match buf.to_original().unwrap() {
api::FlashResult::Pass => Ok(true),
api::FlashResult::Fail => Ok(false),
}
}

pub fn flash_program(&mut self, addr: u32, page: [Option<[u8; 256]>; 4]) -> Result<bool, xous::Error> {
if !self.ec_acquired {
return Err(xous::Error::AccessDenied);
}
let flashop =
api::FlashRecord { id: self.ec_lock_id.unwrap(), op: api::FlashOp::Program(addr, page) };
let mut buf = Buffer::into_buf(flashop).or(Err(xous::Error::InternalError))?;
buf.lend_mut(self.conn, Opcode::FlashOp.to_u32().unwrap())
.expect("couldn't send flash program command");
match buf.to_original().unwrap() {
api::FlashResult::Pass => Ok(true),
api::FlashResult::Fail => Ok(false),
}
}

/// Reads a page of data out of the EC, starting at address \\`addr\\`. Always reads 256 bytes.
/// The address is in absolute addressing in the EC space, which means this routine, rather
/// deliberately, could be used to also read RAM and CSRs in the EC...
pub fn flash_verify(&mut self, addr: u32, page: &mut [u8; 256]) -> Result<(), xous::Error> {
if !self.ec_acquired {
return Err(xous::Error::AccessDenied);
}
let flashop =
api::FlashRecord { id: self.ec_lock_id.unwrap(), op: api::FlashOp::Verify(addr, [0u8; 256]) };
let mut buf = Buffer::into_buf(flashop).or(Err(xous::Error::InternalError))?;
buf.lend_mut(self.conn, Opcode::FlashOp.to_u32().unwrap())
.expect("couldn't send flash program command");
let ret = buf.to_original::<api::FlashRecord, _>().unwrap();
match ret.op {
FlashOp::Verify(_a, d) => {
page.copy_from_slice(&d);
Ok(())
}
_ => Err(xous::Error::InternalError),
}
}

/// This blocks until the COM responds from initializing the Wifi chip
pub fn wlan_set_on(&mut self) -> Result<xous::Result, xous::Error> {
send_message(self.conn, Message::new_blocking_scalar(Opcode::WlanOn.to_usize().unwrap(), 0, 0, 0, 0))
}

pub fn wlan_set_off(&mut self) -> Result<xous::Result, xous::Error> {
send_message(self.conn, Message::new_scalar(Opcode::WlanOff.to_usize().unwrap(), 0, 0, 0, 0))
}

pub fn wlan_set_ssid(&mut self, s: &str) -> Result<xous::Result, xous::Error> {
use core::fmt::Write;
// Enforce WF200 driver API length limit
if s.len() > api::WF200_SSID_MAX_LEN {
return Err(xous::Error::InvalidString);
}
let mut copy = String::new();
let _ = write!(copy, "{}", s);
let buf = Buffer::into_buf(copy).or(Err(xous::Error::InternalError))?;
buf.lend(self.conn, Opcode::WlanSetSSID.to_u32().unwrap())
}

pub fn wlan_set_pass(&mut self, s: &str) -> Result<xous::Result, xous::Error> {
use core::fmt::Write;
// Enforce WF200 driver API length limit
if s.len() > api::WF200_PASS_MAX_LEN {
return Err(xous::Error::InvalidString);
}
let mut copy = String::new();
let _ = write!(copy, "{}", s);
let buf = Buffer::into_buf(copy).or(Err(xous::Error::InternalError))?;
buf.lend(self.conn, Opcode::WlanSetPass.to_u32().unwrap())
}

pub fn wlan_join(&mut self) -> Result<xous::Result, xous::Error> {
send_message(self.conn, Message::new_scalar(Opcode::WlanJoin.to_usize().unwrap(), 0, 0, 0, 0))
}

pub fn wlan_leave(&mut self) -> Result<xous::Result, xous::Error> {
send_message(self.conn, Message::new_scalar(Opcode::WlanLeave.to_usize().unwrap(), 0, 0, 0, 0))
}

/// Note: applications should poll the \\`NetManager::read_wifi_state()\\` call for wifi status information,
/// not the COM directly. This is because the \\`wlan_status\\` call is fairly heavy weight, and the
/// \\`NetManager::read_wifi_state()\\` will cache this information making the status check lighter-weight
/// overall.
pub fn wlan_status(&self) -> Result<WlanStatus, xous::Error> {
let status = WlanStatusIpc::default();
let mut buf = Buffer::into_buf(status).or(Err(xous::Error::InternalError))?;
buf.lend_mut(self.conn, Opcode::WlanStatus.to_u32().unwrap()).or(Err(xous::Error::InternalError))?;
let response = buf.to_original::<WlanStatusIpc, _>().unwrap();
Ok(WlanStatus::from_ipc(response))
}

pub fn wlan_get_config(&self) -> Result<Ipv4Conf, xous::Error> {
let prealloc = Ipv4Conf::default().encode_u16();
let mut buf = Buffer::into_buf(prealloc).or(Err(xous::Error::InternalError))?;
buf.lend_mut(self.conn, Opcode::WlanGetConfig.to_u32().expect("WlanGetConfig failed"))
.or(Err(xous::Error::InternalError))?;
let response = buf.to_original().expect("Couldn't convert WlanGetConfig buffer");
let config = Ipv4Conf::decode_u16(&response);
if (config.mac[0] & 0xFE) == 0x01 || (config.addr[0] & 0xF0) == 0xE0 {
// something is wrong with the COM; probably the link is being reset or not in a proper state.
Err(xous::Error::BadAddress)
} else {
Ok(config)
}
}

pub fn wlan_debug(&self) -> Result<WlanDebug, xous::Error> {
let prealloc = WlanDebug::default();
let mut buf = Buffer::into_buf(prealloc).or(Err(xous::Error::InternalError))?;
buf.lend_mut(self.conn, Opcode::WlanDebug.to_u32().expect("WlanDebug failed"))
.or(Err(xous::Error::InternalError))?;
let response = buf.to_original().expect("Couldn't convert WlanDebug buffer");
Ok(response)
}

pub fn wlan_fetch_packet(&self, pkt: &mut [u8]) -> Result<(), xous::Error> {
if pkt.len() > NET_MTU {
return Err(xous::Error::OutOfMemory);
}
let mut prealloc: [u8; NET_MTU] = [0; NET_MTU];
let len_bytes = (pkt.len() as u16).to_be_bytes();
prealloc[0] = len_bytes[0];
prealloc[1] = len_bytes[1];
let mut buf = Buffer::into_buf(prealloc).or(Err(xous::Error::InternalError))?;
buf.lend_mut(self.conn, Opcode::WlanFetchPacket.to_u32().expect("WlanFetchPacket failed"))
.or(Err(xous::Error::InternalError))?;
let response = buf.as_flat::<[u8; NET_MTU], _>().expect("couldn't convert WlanFetchPacket buffer");
for (&src, dst) in response.iter().zip(pkt.iter_mut()) {
*dst = src;
}
Ok(())
}

pub fn wlan_fetch_loopback_packet(&self, pkt: &mut [u8]) -> Result<(), xous::Error> {
// this is a hack to make loopbacks work on smoltcp. Work-around taken from Redox, but tracking this
// issue as well: https://github.com/smoltcp-rs/smoltcp/issues/50 and https://github.com/smoltcp-rs/smoltcp/issues/55
// Inject the loopback packets. loopback packets always take priority, for now.
if let Some(loop_packet) = self.loopback_buf.borrow_mut().pop_front() {
// pkt.len() is almost always not loop_packet.len(), just copy the first bit that can fit and the
// rest is garbarge...
for (&s, d) in loop_packet.iter().zip(pkt.iter_mut()) {
*d = s;
}
}
Ok(())
}

// this is a hack to make loopbacks work on smoltcp. Work-around taken from Redox, but tracking this issue
// as well: https://github.com/smoltcp-rs/smoltcp/issues/50 and https://github.com/smoltcp-rs/smoltcp/issues/55
// this function handles enqueuing packets for local injection
pub fn wlan_queue_loopback(&self, pk: &[u8]) { self.loopback_buf.borrow_mut().push_back(pk.to_vec()); }

pub fn wlan_send_packet(&self, pkt: &[u8]) -> Result<(), xous::Error> {
if pkt.len() > NET_MTU {
return Err(xous::Error::OutOfMemory);
}
let mut prealloc: [u8; NET_MTU + 2] = [0; NET_MTU + 2];
let len_bytes = (pkt.len() as u16).to_be_bytes();
prealloc[0] = len_bytes[0];
prealloc[1] = len_bytes[1];
for (&src, dst) in pkt.iter().zip(prealloc[2..].iter_mut()) {
*dst = src;
}
let buf = Buffer::into_buf(prealloc).or(Err(xous::Error::InternalError))?;
buf.send(self.conn, Opcode::WlanSendPacket.to_u32().expect("WlanSendPacket failed"))
.or(Err(xous::Error::InternalError))?;
Ok(())
}

/// signal strength in -dBm (pre-negated, for "proper" reporting, add a - sign)
pub fn wlan_get_rssi(&self) -> Result<u8, xous::Error> {
let response = send_message(
self.conn,
Message::new_blocking_scalar(Opcode::WlanRssi.to_usize().unwrap(), 0, 0, 0, 0),
)
.expect("couldn't send WlanRssi message");
if let xous::Result::Scalar1(rssi_usize) = response {
if rssi_usize & 0xFF_00 != 0 {
log::error!("got an error code in fetching the RSSI data: 0x{:x}", rssi_usize);
Err(xous::Error::UnknownError)
} else {
// must convert raw code to signal strength here
let rssi = 110u8 - (rssi_usize & 0xFF) as u8;
log::debug!("RSSI (lib): -{}dBm", rssi);
Ok(rssi)
}
} else {
Err(xous::Error::InternalError)
}
}

pub fn wlan_sync_state(&self) -> Result<(LinkState, DhcpState), xous::Error> {
let response = send_message(
self.conn,
Message::new_blocking_scalar(Opcode::WlanSyncState.to_usize().unwrap(), 0, 0, 0, 0),
)
.expect("couldn't send WlanRssi message");
if let xous::Result::Scalar2(link, dhcp) = response {
Ok((LinkState::decode_u16(link as u16), DhcpState::decode_u16(dhcp as u16)))
} else {
Err(xous::Error::InternalError)
}
}

pub fn wlan_is_reset_hold(&self) -> Result<bool, xous::Error> {
let status = self.wlan_status()?;
if status.link_state == LinkState::ResetHold { Ok(true) } else { Ok(false) }
}

pub fn ints_enable(&self, int_list: &[ComIntSources]) {
let mut mask_val: u16 = 0;
for &item in int_list.iter() {
let item_as_u16: u16 = item.into();
mask_val |= item_as_u16;
}
let _ = send_message(
self.conn,
Message::new_blocking_scalar(Opcode::IntSetMask.to_usize().unwrap(), mask_val as usize, 0, 0, 0),
)
.expect("couldn't send IntSetMask message");
}

pub fn ints_get_enabled(&self, int_list: &mut Vec<ComIntSources>) {
let response = send_message(
self.conn,
Message::new_blocking_scalar(Opcode::IntGetMask.to_usize().unwrap(), 0, 0, 0, 0),
)
.expect("Couldn't get IntGetMask");
if let xous::Result::Scalar1(raw_mask) = response {
let mut mask_bit: u16 = 1;
for _ in 0..16 {
let int_src = ComIntSources::from(mask_bit & raw_mask as u16);
if int_src != ComIntSources::Invalid {
int_list.push(int_src);
}
mask_bit <<= 1;
}
} else {
panic!("failed to send IntGetmask message");
}
}

pub fn ints_ack(&self, int_list: &[ComIntSources]) {
let mut ack_val: u16 = 0;
for &item in int_list.iter() {
let item_as_u16: u16 = item.into();
ack_val |= item_as_u16;
}
let _ = send_message(
self.conn,
Message::new_blocking_scalar(Opcode::IntAck.to_usize().unwrap(), ack_val as usize, 0, 0, 0),
)
.expect("couldn't send IntSetMask message");
}

pub fn ints_get_active(
&self,
int_list: &mut Vec<ComIntSources>,
) -> Result<(Option<u16>, usize, usize), xous::Error> {
let response = send_message(
self.conn,
Message::new_blocking_scalar(Opcode::IntFetchVector.to_usize().unwrap(), 0, 0, 0, 0),
)
.expect("couldn't get IntFetchVector");
let mut rxlen: Option<u16> = None;
if let xous::Result::Scalar2(ints, maybe_rxlen) = response {
if ints == 0xDDDD {
log::warn!("IntFetchVector: 0xDDDD sentinel returned");
return Err(xous::Error::Timeout);
}
let mut mask_bit: u16 = 1;
for _ in 0..16 {
let int_src = ComIntSources::from(mask_bit & ints as u16);
if int_src != ComIntSources::Invalid {
int_list.push(int_src);
if maybe_rxlen > NET_MTU {
log::error!(
"got an RX_LEN bigger than NET_MTU: {}, squashing packet; ints vector: 0x{:x?}",
maybe_rxlen,
ints
);
rxlen = None;
} else {
if int_src == ComIntSources::WlanRxReady {
rxlen = Some(maybe_rxlen as u16);
} else if int_src == ComIntSources::Connect {
rxlen = Some(maybe_rxlen as u16);
}
}
}
mask_bit <<= 1;
}
Ok((rxlen, ints, maybe_rxlen))
} else {
panic!("failed to send IntGetmask message");
}
}
}

use core::sync::atomic::{AtomicU32, Ordering};
static REFCOUNT: AtomicU32 = AtomicU32::new(0);
impl Drop for Com {
fn drop(&mut self) {
// if we have callbacks, destroy the battstats callback server
if let Some(sid) = self.battstats_sid.take() {
// no need to tell the COM server we're quitting: the next time a callback processes,
// it will automatically remove my entry as it will receive a ServerNotFound error.

// tell my handler thread to quit
let cid = xous::connect(sid).unwrap();
xous::send_message(cid, Message::new_scalar(api::Callback::Drop.to_usize().unwrap(), 0, 0, 0, 0))
.unwrap();
unsafe {
xous::disconnect(cid).unwrap();
}
}
// now de-allocate myself. It's unsafe because we are responsible to make sure nobody else is using
// the connection.
if REFCOUNT.fetch_sub(1, Ordering::Relaxed) == 1 {
unsafe {
xous::disconnect(self.conn).unwrap();
}
}
}
}

Served by rngit 1.4.0 - Generated in 0.08s